using System;
using System.Collections;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;


/// <summary>
/// Summary description for CompressFolder
/// </summary>

namespace NNS.Utils.Utils
{
    /// <summary>
    /// 11/08/2010
    /// </summary>
    public class ZipHelper
    {
        #region Delegate
        public delegate void UnzipProcessEventHander(object sender, int position);

        public event UnzipProcessEventHander UnzipProcess;

        private void OnUnzipProcess(int position)
        {
            if (UnzipProcess != null) UnzipProcess(null, position);
        }

        public delegate void UnzipFailEventHander(object sender, String Message);

        public event UnzipFailEventHander UnzipFail;

        private void OnUnzipFail(String Message)
        {
            if (UnzipFail != null) UnzipFail(null, Message);
        }
        
        public event EventHandler UnzipComplete;

        private void OnUnzipComplete(EventArgs e)
        {
            EventHandler complete = UnzipComplete;
            if (complete != null) complete(this, e);
        }

        public event EventHandler<ExtractFileChangedEventArg> ExtractFileChanged;

        
        void OnExtractFileChanged(ExtractFileChangedEventArg e)
        {
            EventHandler<ExtractFileChangedEventArg> handler = ExtractFileChanged;
            if (handler != null) handler(this, e);
        }

        #endregion

        #region Method
        public ZipHelper()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        public void ZipFile(string sPath, string descZipFile)
        {
            ZipOutputStream zipOut = new ZipOutputStream(File.Create(descZipFile));

            FileInfo fi = new FileInfo(sPath);
            ZipEntry entry = new ZipEntry(fi.Name);
            FileStream sReader = File.OpenRead(sPath);
            byte[] buff = new byte[Convert.ToInt32(sReader.Length)];
            sReader.Read(buff, 0, (int)sReader.Length);
            entry.DateTime = fi.LastWriteTime;
            entry.Size = sReader.Length;
            sReader.Close();
            zipOut.PutNextEntry(entry);
            zipOut.Write(buff, 0, buff.Length);
            zipOut.Finish();
            zipOut.Close();
        }

        public void ZipFolder(string inputFolderPath, string outputPathAndFile)
        {
            ArrayList ar = GenerateFileList(inputFolderPath); // generate file list
            int TrimLength = (Directory.GetParent(inputFolderPath)).ToString
    ().Length;
            // find number of chars to remove     // from orginal file path
            TrimLength += 1; //remove '\'
            FileStream ostream;
            byte[] obuffer;
            string outPath = inputFolderPath + @"\" + outputPathAndFile;
            ZipOutputStream oZipStream = new ZipOutputStream(File.Create
    (outPath)); // create zip stream

            oZipStream.SetLevel(9); // maximum compression
            ZipEntry oZipEntry;
            foreach (string Fil in ar) // for each file, generate a zipentry
            {
                oZipEntry = new ZipEntry(Fil.Remove(0, TrimLength));
                oZipStream.PutNextEntry(oZipEntry);

                if (!Fil.EndsWith(@"/")) // if a file ends with '/' its a directory
                {
                    ostream = File.OpenRead(Fil);
                    obuffer = new byte[ostream.Length];
                    ostream.Read(obuffer, 0, obuffer.Length);
                    oZipStream.Write(obuffer, 0, obuffer.Length);
                }
            }
            oZipStream.Finish();
            oZipStream.Close();
        }

        public string Extract(string ZipPath, string UnzipPath)
        {
            try
            {
                OnUnzipProcess(0);
                ZipInputStream s = new ZipInputStream(File.OpenRead(ZipPath));
                ZipEntry ZEntry;
                FileStream streamWriter = null;
                string tempDir = "";
                string sFileName = "";

                while ((ZEntry = s.GetNextEntry()) != null)
                {
                    OnExtractFileChanged(new ExtractFileChangedEventArg(ZEntry));

                    long m_Position = 0;
                    string directoryName = "";
                    string strdirectoryName = "";
                    try
                    {

                        directoryName = Path.GetDirectoryName(ZEntry.Name);
                        if (!Directory.Exists(UnzipPath + "\\" + directoryName))
                        {
                            Directory.CreateDirectory(UnzipPath + "\\" + directoryName);
                        }
                    }
                    catch (Exception ex)
                    {
                        //throw new ApplicationException(ex.Message);
                        OnUnzipFail(ex.Message);
                        return "";
                    }

                    sFileName = Path.GetFileName(ZEntry.Name);
                    try
                    {
                        if (sFileName != String.Empty)
                        {
                            streamWriter = File.Create(UnzipPath + "\\" + directoryName + "\\" + sFileName);

                            int size = 20480;
                            byte[] data = new byte[20480];
                            while (true)
                            {
                                size = s.Read(data, 0, data.Length);
                                m_Position += size;
                                OnUnzipProcess((int)((double)m_Position / (double)ZEntry.Size * 100));
                                if (size > 0)
                                {
                                    streamWriter.Write(data, 0, size);
                                }
                                else
                                {
                                    break;
                                }
                            }

                            streamWriter.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        //throw new ApplicationException(ex.Message);
                        OnUnzipFail(ex.Message);
                        return "";
                    }
                }

                if (streamWriter != null)
                {
                    streamWriter.Close();
                }
                s.Close();
                OnUnzipComplete(new EventArgs());
                return sFileName;
            }
            catch (Exception ex)
            {
                OnUnzipFail(ex.Message);
                return ex.Message;

            }
        }

        private ArrayList GenerateFileList(string Dir)
        {
            ArrayList fils = new ArrayList();
            bool Empty = true;
            foreach (string file in Directory.GetFiles(Dir))
            {
                fils.Add(file);
                Empty = false;
            }

            if (Empty)
            {
                if (Directory.GetDirectories(Dir).Length == 0)
                {
                    fils.Add(Dir + @"/");
                }
            }

            foreach (string dirs in Directory.GetDirectories(Dir))
            {
                foreach (object obj in GenerateFileList(dirs))
                {
                    fils.Add(obj);
                }
            }
            return fils;
        } 
        #endregion
        
    }

    public class ExtractFileChangedEventArg:EventArgs
    {
        private ZipEntry _zEntry;
        public ZipEntry ZEntry
        {
            get { return _zEntry; }
        }
        public ExtractFileChangedEventArg(ZipEntry entry)
        {
            _zEntry = entry;
        }

    }
}